/**
 * 防抖类，用于延迟执行回调函数
 */
interface DebounceConfig {
  /**
   * 初始延迟时间（毫秒）。
   * 这是在第一次调用时使用的延迟时间
   */
  initialDelay: number

  /**
   * 后续调用的延迟时间（毫秒）
   * 这是在连续调用时使用的延迟时间
   */
  subsequentDelay: number

  /**
   * 回调函数。
   * 当延迟时间过后，此函数将被调用，并传入相应的数据
   * @param data - 传递给回调的数据
   */
  callback: (data: string) => void
}

class SectionDelay {
  /**
   * 存储定时器的 ID，用于取消定时器
   * 如果没有设置定时器，则为 null
   */
  private timer: NodeJS.Timeout | null = null

  /**
   * 存储防抖功能的配置。
   * 包含初始延迟、后续延迟和回调函数
   */
  private config: DebounceConfig

  /**
   * 上一次处理的数据
   */
  private lastData: string = ''

  /**
   * 类构造器，接受防抖功能的配置。
   * @param config - 包含初始延迟、后续延迟和回调函数的配置对象。
   */
  constructor(config: DebounceConfig) {
    this.config = config
  }

  /**
   * 防抖方法，用于延迟执行回调函数
   * @param {string} data - 传递给回调函数的数据
   */
  public debounce(data: string): void {
    if (
      [
        // 不存在挂起的定时器
        this.timer === null,
        // 上次数据与这次数据不相同，才继续延迟识别
        this.lastData !== data,
      ].some(Boolean)
    ) {
      // 设置新的待处理数据和回调
      this.lastData = data

      // 调用定时器方法
      this.scheduleNextTick()
    }
  }

  /**
   * 设置定时器
   */
  private scheduleNextTick(): void {
    // 计算延迟时间，如果是连续调用则使用后续延迟，否则使用初始延迟
    const delay = this.timer ? this.config.subsequentDelay : this.config.initialDelay

    // 取消之前的定时器
    this.cancelTimer()

    // 设置新的定时器
    this.timer = setTimeout(() => {
      this.execute()
    }, delay)
  }

  /**
   * 立即执行方法，取消挂起的定时器并立即执行回调
   */
  public immediateDebounce(): void {
    this.cancelTimer()
    this.execute()
  }

  /**
   * 执行方法，调用存储的回调函数
   * 如果存在挂起的回调，则执行它
   */
  private execute(): void {
    this.config.callback(this.lastData || '')
    this.reset()
  }

  /**
   * 取消定时器方法，停止尚未执行的定时器
   */
  private cancelTimer(): void {
    if (this.timer !== null) {
      clearTimeout(this.timer)
      this.timer = null
    }
  }

  /**
   * 重置方法，重置所有挂起的状态
   */
  private reset(): void {
    this.lastData = ''
    this.timer = null
  }
}

export {
  SectionDelay,
}
